/*
   nSS * * SCK
   IRQ * * MOSI
  MISO * * RST
  XOUT * * PACTL
  FGND * * VCC
 RX_EN * * TX_EN  
 */
enum {
	CYRF_00_CHANNEL        = 0x01,
	CYRF_01_TX_LENGTH      = 0x01,
	CYRF_02_TX_CTRL        = 0x02,
	CYRF_03_TX_CFG         = 0x03,
	CYRF_04_TX_IRQ_STATUS  = 0x04,
	CYRF_05_RX_CTRL        = 0x05,
	CYRF_06_RX_CFG         = 0x06,
	CYRF_07_RX_IRG_STATUS  = 0x07,
	CYRF_08_RX_STATUS      = 0x08,
	CYRF_09_RX_COUNT       = 0x09,
	CYRF_0A_RX_LENGTH      = 0x0A,
	CYRF_0B_PWR_CTRL       = 0x0B,
	CYRF_0C_XTAL_CTRL      = 0x0C,
	CYRF_0D_IO_CFG         = 0x0D,
	CYRF_0E_GPIO_CTRL      = 0x0E,
	CYRF_0F_XACT_CFG       = 0x0F,
	CYRF_10_FRAMING_CFG    = 0x10,
	CYRF_11_DATA32_THOLD   = 0x11,
	CYRF_12_DATA64_THOLD   = 0x12,
	CYRF_13_RSSI           = 0x13,
	CYRF_14_EOP_CTRL       = 0x14,
	CYRF_15_CRC_SEED_LSB   = 0x15,
	CYRF_16_CRC_SEED_MSB   = 0x16,
	CYRF_17_TX_CRC_LSB     = 0x17,
	CYRF_18_TX_CRC_MSB     = 0x18,
	CYRF_19_RX_CRC_LSB     = 0x19,
	CYRF_1A_RX_CRC_MSB     = 0x1A,
	CYRF_1B_TX_OFFSET_LSB  = 0x1B,
	CYRF_1C_TX_OFFSET_MSB  = 0x1C,
	CYRF_1D_MODE_OVERRIDE  = 0x1D,
	CYRF_1E_RX_OVERRIDE    = 0x1E,
	CYRF_1F_TX_OVERRIDE    = 0x1F,
	CYRF_20_TX_BUFFER      = 0x20,
	CYRF_21_RX_BUFFER      = 0x21,
	CYRF_22_SOP_CODE       = 0x22,
	CYRF_23_DATA_CODE      = 0x23,
	CYRF_24_PREAMBLE       = 0x24,
	CYRF_25_MFG_ID         = 0x25,
	CYRF_26_XTAL_CFG       = 0x26,
	CYRF_27_CLK_OVERRIDE   = 0x27,
	CYRF_28_CLK_EN         = 0x28,
	CYRF_29_RX_ABORT       = 0x29,
	CYRF_32_AUTO_CAL_TIME  = 0x32,
	CYRF_35_AUTOCAL_OFFSET = 0x35,
	CYRF_39_ANALOG_CTRL    = 0x39,
};

#define CYRF_CS 10
#define CYRF_RS 9

#define CYRF_WRITE (0x80)
#define CYRF_ADR_MASK (0x3F)

#define RX_GO (0x80)

inline void CS_LO(void){
	digitalWrite(CYRF_CS,LOW);
}
inline void CS_HI(void){
	digitalWrite(CYRF_CS,HIGH);
}
inline void RS_LO(void){
	digitalWrite(CYRF_RS,LOW);
}
inline void RS_HI(void){
	digitalWrite(CYRF_RS,HIGH);
}
void CYRF_WriteRegister(byte address, byte data)
{
	address&=CYRF_ADR_MASK;
	address|=CYRF_WRITE;
	CS_LO();
	SPI.transfer(address);
	SPI.transfer(data);
	CS_HI();
}

static void WriteRegisterMulti(byte address, const byte data[], byte length)
{
	address&=CYRF_ADR_MASK;
	address|=CYRF_WRITE;
	unsigned char i;
	CS_LO();
	SPI.transfer(address);
	for(i = 0; i < length; i++)
	{
		SPI.transfer(data[i]);
	}
	CS_HI();
}

static void ReadRegisterMulti(byte address, byte data[], byte length)
{
	address&=CYRF_ADR_MASK;
	unsigned char i;
	CS_LO();
	SPI.transfer(address);
	for(i = 0; i < length; i++)
	{
		data[i]=SPI.transfer( 0);
	}
	CS_HI();
}

byte CYRF_ReadRegister(byte address)
{
	address&=CYRF_ADR_MASK;
	byte data;

	CS_LO();
	SPI.transfer(address);
	data = SPI.transfer(0);
	CS_HI();
	return data;
}

void CYRF_Reset()
{
	/* Reset the CYRF chip */
	RS_HI();
	delay(100);
	RS_LO();
	delay(100);
}

/*
* 1 - Tx else Rx
*/
void CYRF_ConfigRxTx(boolean TxRx)
{
	if(TxRx)
	{
		CYRF_WriteRegister(0x0E,0x80);
		CYRF_WriteRegister(0x0F,0x2C);
	}
	else
	{
		CYRF_WriteRegister(0x0E,0x20);
		CYRF_WriteRegister(0x0F,0x28);
	}
}

void CYRF_ConfigCRCSeed(word crc)
{
	CYRF_WriteRegister(0x15,crc & 0xff);
	CYRF_WriteRegister(0x16,crc >> 8);
}

/*
 * these are the recommended sop codes from Crpress
 * See "WirelessUSB LP/LPstar and PRoC LP/LPstar Technical Reference Manual"
 */
void CYRF_ConfigSOPCode(const byte *sopcodes)
{
	//NOTE: This can also be implemented as:
	//for(i = 0; i < 8; i++) WriteRegister)0x23, sopcodes[i];
	WriteRegisterMulti(CYRF_22_SOP_CODE, sopcodes, 8);
}


void CYRF_ConfigDataCode(const byte *datacodes, byte len)
{
	//NOTE: This can also be implemented as:
	//for(i = 0; i < len; i++) WriteRegister)0x23, datacodes[i];
	WriteRegisterMulti(CYRF_23_DATA_CODE, datacodes, len);
}

void CYRF_WritePreamble(unsigned long preamble)
{
	CS_LO();
	SPI.transfer((CYRF_ADR_MASK&CYRF_24_PREAMBLE)|CYRF_WRITE);
	SPI.transfer(preamble & 0xff);
	SPI.transfer((preamble >> 8) & 0xff);
	SPI.transfer((preamble >> 16) & 0xff);
	CS_HI();
}

void CYRF_Init()
{
	/* Initialise CYRF chip */
	CYRF_WriteRegister(CYRF_1D_MODE_OVERRIDE, 0x39);
	CYRF_WriteRegister(CYRF_03_TX_CFG, 0x08 | 7);
	CYRF_WriteRegister(CYRF_06_RX_CFG, 0x4A);
	CYRF_WriteRegister(CYRF_0B_PWR_CTRL, 0x00);
	CYRF_WriteRegister(CYRF_0D_IO_CFG, 0x04);
	CYRF_WriteRegister(CYRF_0E_GPIO_CTRL, 0x20);
	CYRF_WriteRegister(CYRF_10_FRAMING_CFG, 0xA4);
	CYRF_WriteRegister(CYRF_11_DATA32_THOLD, 0x05);
	CYRF_WriteRegister(CYRF_12_DATA64_THOLD, 0x0E);
	CYRF_WriteRegister(CYRF_1B_TX_OFFSET_LSB, 0x55);
	CYRF_WriteRegister(CYRF_1C_TX_OFFSET_MSB, 0x05);
	CYRF_WriteRegister(CYRF_32_AUTO_CAL_TIME, 0x3C);
	CYRF_WriteRegister(CYRF_35_AUTOCAL_OFFSET, 0x14);
	CYRF_WriteRegister(CYRF_39_ANALOG_CTRL, 0x01);
	CYRF_WriteRegister(CYRF_1E_RX_OVERRIDE, 0x10);
	CYRF_WriteRegister(CYRF_1F_TX_OVERRIDE, 0x00);
	CYRF_WriteRegister(CYRF_01_TX_LENGTH, 0x10);
	CYRF_WriteRegister(CYRF_0C_XTAL_CTRL, 0xC0);
	CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x10);
	CYRF_WriteRegister(CYRF_27_CLK_OVERRIDE, 0x02);
	CYRF_WriteRegister(CYRF_28_CLK_EN, 0x02);
	CYRF_WriteRegister(CYRF_0F_XACT_CFG, 0x28);
}

void CYRF_GetMfgData(byte data[])
{
	/* Fuses power on */
	CYRF_WriteRegister(CYRF_25_MFG_ID, 0xFF);

	ReadRegisterMulti(CYRF_25_MFG_ID, data, 6);

	/* Fuses power off */
	CYRF_WriteRegister(CYRF_25_MFG_ID, 0x00); 
}

void CYRF_StartReceive()
{
	CYRF_WriteRegister(CYRF_05_RX_CTRL,0x87);
}

byte CYRF_ReadRSSI(unsigned long dodummyread)
{
	byte result;
	if(dodummyread)
	{
		result = CYRF_ReadRegister(CYRF_13_RSSI);
	}
	result = CYRF_ReadRegister(CYRF_13_RSSI);
	if(result & 0x80)
	{
		result = CYRF_ReadRegister(CYRF_13_RSSI);
	}
	return (result & 0x0F);
}

//NOTE: This routine will reset the CRC Seed
void CYRF_FindBestChannels(byte *channels, byte len, byte minspace, byte min, byte max)
{
#define NUM_FREQ 80
#define FREQ_OFFSET 4
	byte rssi[NUM_FREQ];

	if (min < FREQ_OFFSET)
		min = FREQ_OFFSET;
	if (max > NUM_FREQ)
		max = NUM_FREQ;

	int i;
	int j;
	memset(channels, 0, sizeof(byte) * len);
	CYRF_ConfigCRCSeed(0x0000);
	CYRF_ConfigRxTx(0);
	//Wait for pre-amp to switch from sned to receive
	delay(1000);
	for(i = 0; i < NUM_FREQ; i++) {
		CYRF_ConfigRFChannel(i);
		CYRF_ReadRegister(CYRF_13_RSSI);
		CYRF_StartReceive();
		delay(10);
		rssi[i] = CYRF_ReadRegister(CYRF_13_RSSI);
	}

	for (i = 0; i < len; i++) {
		channels[i] = min;
		for (j = min; j < max; j++) {
			if (rssi[j] < rssi[channels[i]]) {
				channels[i] = j;
			}

		}
		for (j = channels[i] - minspace; j < channels[i] + minspace; j++) {
			//Ensure we don't reuse any channels within minspace of the selected channel again
			if (j < 0 || j >= NUM_FREQ)
				continue;
			rssi[j] = 0xff;
		}
	}
	CYRF_ConfigRxTx(1);
}

/*
 *
 */
void CYRF_ConfigRFChannel(byte ch)
{
	Serial.print("Channel:");
	Serial.println(ch);
	CYRF_WriteRegister(CYRF_00_CHANNEL,ch);
}
void CYRF_ReadDataPacket(byte dpbuffer[])
{
	ReadRegisterMulti(CYRF_21_RX_BUFFER, dpbuffer, 0x10);
}

void CYRF_WriteDataPacketLen(const byte dpbuffer[], byte len)
{
	CYRF_WriteRegister(CYRF_01_TX_LENGTH, len);
	CYRF_WriteRegister(CYRF_02_TX_CTRL, 0x40);
	WriteRegisterMulti(CYRF_20_TX_BUFFER, dpbuffer, len);
	CYRF_WriteRegister(CYRF_02_TX_CTRL, 0xBF);
}

void CYRF_WriteDataPacket(const byte dpbuffer[])
{
	CYRF_WriteDataPacketLen(dpbuffer, 16);
}

void CYRF_SetPower(byte power)
{
	byte val = CYRF_ReadRegister(CYRF_03_TX_CFG) & 0xF8;
	CYRF_WriteRegister(CYRF_03_TX_CFG, val | (power & 0x07));
}
